import { any, must } from "../core/logic";
import { Vector3 } from "../core/math/Vector3"
import { Geometry } from "./Geometry";
import { process } from "../process/worker/process";
import { genOneLine } from "./Utile/Utile";
/**
 * 材质类。
 * @class
 * @extends w.geometry.Geometry
 * @memberof w.geometry
 */
class LineGeometry extends Geometry {
    /**
     * 创建材质
     * @constructor
     * @param {*} opts
     * @param {Number} opts.lineWidth 【可选,缺省:40】线宽。
     * @param {Number} opts.map_uvPixel 【可选,缺省:40】单个贴图所占像素。
     * @param {Array} opts.map_uvOffset 【可选,缺省:[0,0]】贴图偏移。
     * @param {String} opts.lineJoint 【可选,缺省:'round'】连接点样式，可选值:"miter"|"bevel"|"round"。
     * @param {Number} opts.jointCount 【可选,缺省:30】连接点补点数量。
     * @param {Number} opts.capCount 【可选,缺省:5】端点补点数量。
     * @example
     * let geometry = new w.geometry.LineGeometry({
     *   position: vex,
     *   capCount: 10,
     *   lineJoint: 'round',//round圆角miter尖角bevel平角
     *   lineWidth: 10,
     *   map_uvPixel: 10,//单个贴图所占像素
     *   map_uvOffset: [0, 0]//贴图偏移
     * })
     */
    constructor(opts = {}, share) {
        let rawPosition = any(opts.position, new Float32Array([]));
        delete opts.position
        opts.autoUpdate=false;
        super(opts);
        this.type="LineGeometry";
        this.geometryType = "LineGeometry";
        this._hash = "";
        this.capCount = any(opts.capCount, 5);
        this.jointCount = any(opts.jointCount, 30);
        this._lineJoint = any(opts.lineJoint, 'round');

        this.rawPosition = rawPosition;
        this.rawColor = this.getPointColors(any(opts.color, new Float32Array([])));
        this.back = any(opts.back, true);
        this.map_uvOffset = any(opts.map_uvOffset, [.0, .0]);
        this.map_uvPixel = any(opts.map_uvPixel, 40);
        this.pixelUnit=any(opts.pixelUnit,true);
        this.lineWidth = any(opts.lineWidth, 40);
        this.calcData = opts.calcData;
        this.processCallback = any(opts.callback, () => { })
        this.setLineAttribute();
    }
    set rawPosition(v) {
        let pos = must(v);
        if (v.length && !Array.isArray(v[0])) {
            pos = [v]
        }
        this._rawPosition = pos;
        this.setLineAttribute();
        return this;
    }
    get rawPosition() {
        return this._rawPosition;
    }
    set pixelUnit(v){
        if(this.pixelUnit!==v){
            this._pixelUnit=v;
            this.addConfigParam("pixelUnit",v);
            this.update();
        }
        return this;
    }
    get pixelUnit(){
        return this._pixelUnit;
    }
    get lineJoint(){
        return this._lineJoint;
    }
    set lineJoint(v){
        if(this.lineJoint!==v){
            this._lineJoint=v;
            this.setLineAttribute();
            this.update();
        }
        return this;
    }
    get lineJoint(){
        return this._lineJoint;
    }
    set pointNormal(v) {
        this._pointNormal = v;
        this.addParam("pointNormal");
        this.update();
        return this;
    }
    get pointNormal() {
        return this._pointNormal;
    }

    set uvWidthFactor(v) {
        this._uvWidthFactor = v;
        this.addParam("uvWidthFactor");
        this.update();
        return this;
    }
    get uvWidthFactor() {
        return this._uvWidthFactor;
    }
    set map_uvOffset(v) {
        this._map_uvOffset = v;
        this.addParam("map_uvOffset");
        this.update();
        return this;
    }
    get map_uvOffset() {
        return this._map_uvOffset;
    }
    set map_uvPixel(v) {
        this._map_uvPixel = v;
        this.addParam("map_uvPixel");
        this.update();
        return this;
    }
    get map_uvPixel() {
        return this._map_uvPixel;
    }

    set lineWidth(v) {
        this._lineWidth = v;
        this.addParam("lineWidth");
        this.update();
        return this;
    }
    get lineWidth() {
        return this._lineWidth;
    }
    getPoints() {
        const points = [];
        for (const rawPosition of this.rawPosition) {
            const noRepeatPoints = [];
            for (let j = 0; j < rawPosition.length; j += 3) {
                const currentPoint = [rawPosition[j], rawPosition[j + 1], rawPosition[j + 2]];
                // 检查是否与最后一个点相同
                if (noRepeatPoints.length === 0 || !this.comparePoint(noRepeatPoints[noRepeatPoints.length - 1], currentPoint)) {
                    // 去除共线点
                    if (noRepeatPoints.length > 1) {
                        const prevPoint = noRepeatPoints[noRepeatPoints.length - 1];
                        const secondPrevPoint = noRepeatPoints[noRepeatPoints.length - 2];
                        const currentDir = new Vector3(currentPoint[0] - prevPoint[0], currentPoint[1] - prevPoint[1], currentPoint[2] - prevPoint[2]).normalize();
                        const prevDir = new Vector3(prevPoint[0] - secondPrevPoint[0], prevPoint[1] - secondPrevPoint[1], prevPoint[2] - secondPrevPoint[2]).normalize();
                        // 检查当前方向与前一个方向是否共线
                        if (Math.abs(currentDir.dot(prevDir)) > 0.999999) {
                            noRepeatPoints.pop(); // 去掉最后一个点
                        }
                    }
                    noRepeatPoints.push(currentPoint);
                }
            }
            points.push(noRepeatPoints);
        }
        return points;
    }
    getPointColors(color) {
        let colors = [];
        for (var j = 0; j < color.length; j += 4) {
            colors.push([color[j], color[j + 1], color[j + 2], color[j + 3]])
        }
        return colors;
    }
    setLineAttribute() {
        this.linePoints = this.getPoints();
        if (this.calcData) {
            let {
                positions,
                indexMap,
                indices_array,
                directions,
                uvWidthFactor,
            } = this.calcData;
            this.autoUpdate = false;
            this.indices = indices_array;
            this.indexMap = indexMap;
            let PositionCom = this.get('Position');
            PositionCom.size = 0;
            this.position = positions;
            this.pointNormal = directions;
            this.uvWidthFactor = uvWidthFactor;
            if (this.rawColor.length) {
                //     let ColorCom = this.get('Color');
                //     ColorCom.size = 0;
                this.color = this.getLineColors(this.rawColor, Array.from(indexMap));
            }
            this.autoUpdate = true;
            this.update();
            this.processCallback(this.calcData);
        } else {


            process({ type: "line", back: this.back, points: this.linePoints, capCount: this.capCount, jointCount: this.jointCount, lineJoint: this.lineJoint, isTile: this.tile }, (message) => {
                let {
                    positions,
                    indexMap,
                    indices_array,
                    directions,
                    uvWidthFactor,
                } = message.data;
                // console.log(message.data)
                this.autoUpdate = false;
                // this.indices = data.indices;
                // // this.indexMap = indexMap;
                // this.position = data.positions;
                // this.pointNormal = data.directions;
                // this.texCood0=data.uvs;
                this.indices = indices_array;
                this.indexMap = indexMap;
                this.position = positions;
                this.pointNormal = directions;
                this.uvWidthFactor = uvWidthFactor;
                if (this.rawColor.length) {
                    //     let ColorCom = this.get('Color');
                    //     ColorCom.size = 0;
                    this.color = this.getLineColors(this.rawColor, Array.from(indexMap));
                }
                this.autoUpdate = true;
                this.update();
                this.processCallback(message.data);
            });
        }

    }
    getLineColors(color, colorIndex) {
        let colors = [];
        for (let i = 0; i < colorIndex.length; i++) {
            colors.push(...color[colorIndex[i]]);
        }
        return new Uint8Array(colors)
    }
    comparePoint(a, b) {
        if (!a || !b) return false;
        return (
            a[0] === b[0] &&
            a[1] === b[1] &&
            a[2] === b[2]
        )
    }
    toGPU() {
        if (this.has("pointNormal")) {
            this.initVertex(this.pointNormal, "pointNormal", 3);
        }
        if (this.has("uvWidthFactor")) {
            this.initVertex(this.uvWidthFactor, "uvWidthFactor", 4);
        }
        if (this.has("map_uvOffset")) {
            let data = this.map_uvOffset;
            this.bufferToGPU(new Float32Array(data), 'map_uvOffset');
        }
        if (this.has("map_uvPixel")) {
            let data = [this.map_uvPixel];
            this.bufferToGPU(new Float32Array(data), 'map_uvPixel');
        }
        if (this.has("lineWidth")) {
            let data = [this.lineWidth];
            this.bufferToGPU(new Float32Array(data), 'lineWidth', GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT);
        }
        super.toGPU();
    }
}

export { LineGeometry };
